package com.atguigu.stream.exer01;

import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;

// 终止操作
public class TestStreamAPI3 {

    List<Emp> employees = Arrays.asList(
            new Emp(101,"张三", 18, 9999.99, Status.FREE),
            new Emp(102,"李四", 38, 5555.99, Status.BUSY),
            new Emp(103,"王五", 50, 6666.66, Status.VOCATION),
            new Emp(104,"赵六", 16, 3333.33, Status.FREE),
            new Emp(104,"赵六", 16, 3333.33, Status.FREE),
            new Emp(105,"田七", 8, 7777.77, Status.BUSY)
    );

    /**
     * 收集：collect 将流转换成其他形式；接收一个 Collector 接口的实现，用于给流中元素做汇总的方法
     */

    // 将所有的名字连起来中间加个逗号展示
    @Test
    public void test10() {
        String str = employees.stream()
                .map(Emp::getName)
                .collect(Collectors.joining(","));
        System.out.println(str);
    }

    // 更快捷的获取总和、平均值、最大值、最小值
    @Test
    public void test9() {
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Emp::getSalary));

        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getMax());
        System.out.println(dss.getMin());
    }

    // 分片，也叫分区
    @Test
    public void test8() {
        Map<Boolean, List<Emp>> map =  employees.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));

        System.out.println(map);
    }

    // 多级分组
    @Test
    public void test7() {
        Map<Status, Map<String, List<Emp>>> map =  employees.stream().collect(Collectors.groupingBy(Emp::getStatus, Collectors.groupingBy((e) -> {
            if (e.getAge() <= 35) {
                return "青年";
            } else if (e.getAge() <= 50) {
                return "中年";
            } else {
                return "老年";
            }
        })));

        System.out.println(map);
    }

    // 分组
    @Test
    public void test6() {
        // 按照状态分组
        Map<Status, List<Emp>> map = employees.stream()
                .collect(Collectors.groupingBy(Emp::getStatus));

        System.out.println(map);
    }

    @Test
    public void test5() {
        // 总数
        Long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);

        // 获取工资的平均值
        Double avg =  employees.stream()
                .collect(Collectors.averagingDouble(Emp::getSalary));
        System.out.println(avg);

        // 求工资总和
        Double sum = employees.stream()
                .collect(Collectors.summingDouble(Emp::getSalary));
        System.out.println(sum);

        // 最大值
        // 按照工资比较获取工资高的员工信息
        Optional<Emp> max = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());

        // 获取最小工资
        Optional<Double> min = employees.stream()
                .map(Emp::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());

    }

    @Test
    public void test4() {
        // 需求：把所有员工的名字提取出来放到一个集合里面去
        List<String> list = employees.stream()
                .map(Emp::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);

        System.out.println("--------------------------------");

        Set<String> set = employees.stream()
                .map(Emp::getName)
                .collect(Collectors.toSet()); // 转成set集合，可去重
        set.forEach(System.out::println);

        System.out.println("-------------------------");

        HashSet<String> hashSet = employees.stream()
                .map(Emp::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hashSet.forEach(System.out::println);


    }


    /**
     * 归约：reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来，得到一个值
     */
    @Test
    public void test3() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y); // 0是起始值，一开始将0赋值给x，然后从流中(list)取值赋值给y，再将x+y赋值给x，依次循环下去。
        System.out.println(sum);

        System.out.println("------------------------------");

        // 需求：计算公司员工工资总和
        // 避免空指针
        Optional<Double> op = employees.stream()
                .map(Emp::getSalary)
                .reduce(Double::sum);
        System.out.println("工资总和：" + op.get());

    }

    /**
     * 查找与匹配：
     * allMatch：检查是否匹配所有元素
     * anyMatch：检查是否至少匹配一个元素
     * noneMatch：检查是否没有匹配所有元素
     * findFirst：返回第一个元素
     * findAny：返回当前流中的任意元素
     * count：返回流中元素的总个数
     * max：返回流中最大值
     * min：返回流中最小值
     *
     */

    @Test
    public void test2() {
        // 计数
        long count = employees.stream()
                .count();
        System.out.println(count);

        // 获取工资最高的人员信息
        Optional<Emp> op1 = employees.stream()
                .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(op1.get());

        // 获取公司最低工资是多少
        Optional<Double> minSalary = employees.stream()
                .map(Emp::getSalary)  // 首先map映射的作用是将所有工资提取出来
                .min(Double::compare); // 将工资进行比较然后找出最低工资
        System.out.println("最低工资是 " + minSalary.get());

    }

    @Test
    public void test1() {
        boolean b1 = employees.stream()
                .allMatch((e) -> e.getStatus().equals(Status.BUSY));
        System.out.println(b1);

        boolean b2 = employees.stream()
                .anyMatch((e) -> e.getStatus().equals(Status.BUSY));
        System.out.println(b2);

        boolean b3 = employees.stream()
                .noneMatch((e) -> e.getStatus().equals(Status.BUSY));
        System.out.println(b3);

        Optional<Emp> op = employees.stream()
                .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();
        System.out.println(op.get());

        System.out.println("----------------------------------------------------");

        Optional<Emp> op2 = employees.parallelStream()  // 并行执行，多线程执行
                .filter((e) -> e.getStatus().equals(Status.FREE))
                .findAny();
        System.out.println(op2.get());


    }

}
